import warnings
import numpy as np
import pandas as pd
from pandas import DataFrame
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.linear_model.coordinate_descent import ConvergenceWarning
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LassoCV,RidgeCV


## 设置字符集，防止中文乱码
mpl.rcParams['font.sans-serif']=[u'simHei']
mpl.rcParams['axes.unicode_minus']=False

columns=['CRIM','ZN','INDUS','CHAS','NOX','RM','AGE','DIS','RAD','TAX','PTRATIO','B','LSTAT']
## 拦截异常
warnings.filterwarnings(action='ignore',category=ConvergenceWarning)

def notEmpty(s):
    return s!=''

def run():
    ## 加载数据
    path='../../data/boston_housing.data'
    ## 由于数据文件格式不统一，所以读取的时候，先按照一行一个字段属性读取数据，然后再安装每行数据进行处理
    df=pd.read_csv(path,header=None)
    arr=np.empty((len(df),14))
    for i,d in enumerate(df.values):#enumerate生成一列索引i,d为其元素
       d=map(float,filter(notEmpty,d[0].split(' '))) #filter一个函数，一个list

       # 根据函数结果是否为真，来过滤list中的项。
       arr[i]=list(d)

    ## 分割数据
    x,y=np.split(arr,(13,),axis=1)
    print(x[0:5])
    y=y.ravel() # 转换格式 拉直操作
    print(y[0:5])
    ly=len(y)
    print(y.shape)
    print("样本数据量:%d, 特征个数：%d" % x.shape)
    print("target样本数据量:%d" % y.shape[0])

    ## Pipeline常用于并行调参
    models=[
        Pipeline([
            ('ss',StandardScaler()),
            ('poly',PolynomialFeatures()),
            ('linear',RidgeCV(alphas=np.logspace(-3,1,20)))
        ]),
        Pipeline([
            ('ss',StandardScaler()),
            ('poly',PolynomialFeatures()),
            ('linear',LassoCV(alphas=np.logspace(-3,1,20)))
        ])
    ]

    # 参数字典， 字典中的key是属性的名称，value是可选的参数列表
    parameters={
        "poly__degree":[3,2,1],
        "poly__interaction_only":[True,False],#不产生交互项，如X1*X1
        "poly__include_bias":[True,False],#多项式幂为零的特征作为线性模型中的截距
        "linear__fit_intercept":[True,False]
    }

    pf=PolynomialFeatures(2,interaction_only=True)
    df_a=DataFrame({
        'name':[1,2,3,4,5],
        'score':[2,3,4,4,5]
    })
    df_b=pf.fit_transform(df_a)

    # 数据分割
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=0)

    ## Lasso和Ridge模型比较运行图表展示
    titles=['Ridge','Lasso']
    colors=['g-','b-']
    plt.figure(figsize=(16,8),facecolor='w')
    k=range(len(x_test))
    plt.plot(k,y_test,'r-',lw=2,label=u'真实值')
    for t in range(2):
        #获取模型并设置参数
        #GridSearchCV: 进行交叉验证，选择出最优的参数值出来
        #第一个输入参数：进行参数选择的模型，param_grid： 用于进行模型选择的参数字段，要求是字典类型；cv: 进行几折交叉验证
        model=GridSearchCV(models[t],param_grid=parameters,cv=5,n_jobs=1)
        # 模型训练-网格搜索
        model.fit(x_train,y_train)
        # 模型效果值获取（最优参数）
        print("%s算法:最优参数:%s" %(titles[t],model.best_params_))
        print("%s算法:R值=%.3f:" % (titles[t],model.best_score_))
        # 模型预测
        y_predict=model.predict(x_test)
        # 画图
        plt.plot(k,y_predict,colors[t],lw=2,label=u'%s算法估计值,R^2=%.3f' %(titles[t],model.best_score_))
    # 图形显示
    plt.title(u"波士顿房屋价格预测")
    plt.legend(loc='uppper left')
    plt.grid(True)
    plt.show()

    model = Pipeline([
        ('ss', StandardScaler()),
        ('poly', PolynomialFeatures(degree=1, include_bias=True, interaction_only=True)),
        ('linear', LassoCV(alphas=np.logspace(-3, 1, 20), fit_intercept=False))
    ])

    # 模型训练
    model.fit(x_train, y_train)

    # 模型评测
    ## 数据输出
    print("参数:", list(zip(columns, model.get_params('linear')['linear'].coef_)))
    print("截距:", model.get_params('linear')['linear'].intercept_)

run()
